package com.fireXXX.job.analysis.crawler.service;

import com.fireXXX.job.analysis.crawler.boss.constant.CityTypeEnum;
import com.fireXXX.job.analysis.crawler.boss.constant.EmployeeNumberTypeEnum;
import com.fireXXX.job.analysis.crawler.boss.constant.IndustryTypeEnum;
import com.fireXXX.job.analysis.crawler.boss.constant.PublicStepTypeEnum;
import com.fireXXX.job.analysis.crawler.boss.progress.CompanyProgress;
import com.fireXXX.job.analysis.crawler.boss.progress.CompanyProgressManager;
import com.fireXXX.job.analysis.crawler.common.*;
import com.fireXXX.job.analysis.crawler.common.company.CompanyCrawler;
import com.fireXXX.job.analysis.crawler.common.company.CompanyTask;
import com.fireXXX.job.analysis.crawler.common.job.JobCrawler;
import com.fireXXX.job.analysis.crawler.error.TaskTypeEndCrawlerException;
import com.fireXXX.job.analysis.crawler.util.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Slf4j
@Service
public class IntegrationService {

    @Autowired
    private CrawlerThreadPool crawlerThreadPool;

    @Autowired
    private CompanyCrawler companyCrawler;

    @Autowired
    private JobCrawler jobCrawler;

    @Autowired
    private DynamicProxy dynamicProxy;

    @Autowired
    private CompanyProgressManager companyProgressManager;

    private enum PageResultEnum {
        SUCCESS,
        FAIL,
        END,
    }

    private void runCompanyProgress(CompanyProgress companyProgress) {
        PageResultEnum result = runPage(companyProgress.getCity(), companyProgress.getIndustry(), companyProgress.getPublicStep(),
                companyProgress.getEmployeeNumber(), companyProgress.getPage());
        while (result != PageResultEnum.END) {
            companyProgressManager.updateProgress(companyProgress);

            if (result == PageResultEnum.FAIL) {
                companyProgressManager.signFail(companyProgress);
            }
            companyProgress.setPage(companyProgress.getPage() + 1);
            result = runPage(companyProgress.getCity(), companyProgress.getIndustry(), companyProgress.getPublicStep(),
                    companyProgress.getEmployeeNumber(), companyProgress.getPage());
        }
    }

    private PageResultEnum runPage(CityTypeEnum city, IndustryTypeEnum industry, PublicStepTypeEnum publicStep, EmployeeNumberTypeEnum employeeNumber, int page) {
        log.info("city({}) industry({}) publicStep({}) employeeNumber({}) page({}) starting......", city, industry, publicStep, employeeNumber, page);

        int retry = 1;
        while (retry < 3) {
            Future result = crawlerThreadPool.submit(
                    new CompanyTask(companyCrawler, city, industry, publicStep, employeeNumber, new Page(page, 30))
            );

            try {
                result.get();
                log.info("city({}) industry({}) publicStep({}) employeeNumber({}) page({}) success......", city, industry, publicStep, employeeNumber, page);
                return PageResultEnum.SUCCESS;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                if (e.getCause() instanceof TaskTypeEndCrawlerException) {
                    return PageResultEnum.END;
                }
                e.printStackTrace();
                log.error("crawlPage city({}) industry({}) publicStep({}) employeeNumber({}), err({})", city, industry.getText(), publicStep.getText(), employeeNumber.getText(), ExceptionUtil.getFirstNonNullMessage(e));
            }

            retry++;
        }

        log.info("city({}) industry({}) publicStep({}) employeeNumber({}) page({}) fail......", city, industry, publicStep, employeeNumber, page);
        return PageResultEnum.FAIL;
    }

    public void runCompanyTask() {
        dynamicProxy.grabNewProxy();

        CompanyProgress companyProgress = companyProgressManager.getCompanyProgress();

        do {
            runCompanyProgress(companyProgress);
        } while (companyProgress.next());
    }

}
